package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"os"
)

type Client struct {
	ServerIp   string
	ServerPort int
	conn       net.Conn
	Name       string
	flag       int
}

func NewClient(serverIp string, serverPort int) *Client {
	client := &Client{
		ServerIp:   serverIp,
		ServerPort: serverPort,
		flag:       999,
	}
	//创建链接
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", serverIp, serverPort))
	if err != nil {
		fmt.Println("net.Dial error:", err)
		return nil
	}
	client.conn = conn
	return client
}

var serverIp string
var serverPort int

// -ip xxx
// -port xxx
func init() {
	flag.StringVar(&serverIp, "ip", "127.0.0.1", "客户端IP地址")
	flag.IntVar(&serverPort, "port", 8888, "客户端端口")
}

//功能菜单
func (s *Client) Menu() bool {
	fmt.Println(">>>>>>>>功能菜单<<<<<<<<<")
	fmt.Println("1、群聊模式")
	fmt.Println("2、私聊模式")
	fmt.Println("3、修改用户名")
	fmt.Println("0、退出")
	fmt.Println(">>>>>>>>>>>><<<<<<<<<<<<")

	var flag int
	//获取输入的数字
	fmt.Scanln(&flag)
	if flag >= 0 && flag <= 3 {
		s.flag = flag
		return true
	} else {
		fmt.Println(">>>>>>>>请输入合法的数字<<<<<<<<<")
		return false
	}
}

func (s *Client) UpdataName() bool {
	fmt.Println("请输入用户名：")
	fmt.Scanln(&s.Name)
	sendMsg := "rename|" + s.Name + "\n"
	_, err := s.conn.Write([]byte(sendMsg))
	if err != nil {
		fmt.Println("修改用户名失败")
		return false
	}
	return true
}

//处理server的回应的消息,直接显示到标准输出,这里可根据业务做判断处理，比如接收到的消息类型，在客户端做不同展示
func (s *Client) Response() {
	//一旦conn有数据，则直接copy到Stdout标准输出，这个是永久阻塞监听的
	io.Copy(os.Stdout, s.conn)
}

//群聊
func (s *Client) PublicChat() {
	//提示用户输入
	fmt.Println("请输入内容，退出输入exit")
	var msg string
	fmt.Scanln(&msg)

	for msg != "exit" {
		if len(msg) != 0 { //	有内容
			sendMsg := msg + "\n"
			//发送给server
			_, err := s.conn.Write([]byte(sendMsg))
			if err != nil {
				fmt.Println("消息发送失败..")
				break
			}
		}
		//无内容
		msg = ""
		fmt.Println("请输入内容，退出输入exit")
		fmt.Scanln(&msg)
	}

}

//查询在线user
func (s *Client) UserOnline() {
	sendMsg := "ls\n"
	_, err := s.conn.Write([]byte(sendMsg))
	if err != nil {
		fmt.Println("online conn.Write error:", err)
		return
	}
}

//私聊
func (s *Client) PrivateChat() {
	//私聊对象
	var remoteName string
	//消息内容
	var chatMsg string

	//显示在线user
	s.UserOnline()
	//提示选择私聊人选
	fmt.Println("请选择私聊人选，退出输入exit")
	//接收输入人选
	fmt.Scanln(&remoteName)
	//判断输入的不是exit
	for remoteName != "exit" {
		//这里不需判断remoteName是否为空，服务端已经判断了

		fmt.Println("请输入私聊消息，退出输入exit")
		fmt.Scanln(&chatMsg)
		for chatMsg != "exit" {
			if len(chatMsg) != 0 {
				//消息不为空，发送
				sendMsg := "to|" + remoteName + "|" + chatMsg + "\n"
				_, err := s.conn.Write([]byte(sendMsg))
				if err != nil {
					fmt.Println("私聊消息发送失败..")
					break
				}
			}
			chatMsg = ""
			fmt.Println("请输入私聊消息，退出输入exit")
			fmt.Scanln(&chatMsg)
		}

		//跑到这里，说明不跟这个人私聊了，可继续选择人私聊，再exit才是退出到主菜单
		remoteName = ""
		//显示在线user
		s.UserOnline()
		//提示选择私聊人选
		fmt.Println("请选择私聊人选，退出输入exit")
		//接收输入人选
		fmt.Scanln(&remoteName)
	}

}

func (s *Client) Handler() {
	for s.flag != 0 {
		for s.Menu() != true {
			//这里输入非法的数字会阻塞在循环里，不会执行下面的语句
		}
		//合法的数字执行下面语句
		switch s.flag {
		case 1:
			s.PublicChat()
			break
		case 2:
			s.PrivateChat()
			break
		case 3:
			s.UpdataName()
			break
		}
	}
}

func main() {
	//命令行解析
	flag.Parse()

	client := NewClient("127.0.0.1", 8888)
	if client != nil {
		fmt.Println(">>>>>>>>>客户端链接服务器成功")
	} else {
		fmt.Println("客户端链接服务器失败")
		return
	}

	//开启一个协程监听server响应
	go client.Response()

	//处理业务
	client.Handler()
}
